package com.freeman.cement.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.freeman.cement.mapper.*;
import com.freeman.cement.entity.*;
import com.freeman.cement.entity.hikvision.EventElement;
import com.freeman.cement.entity.hikvision.HikResultObject;
import com.freeman.cement.myenum.Enabled;
import com.freeman.cement.myenum.ProcessingFlow;
import com.freeman.cement.service.DutyRoomService;
import com.freeman.cement.service.EventAnalysisService;
import com.freeman.cement.service.EventHandleService;
import com.freeman.cement.service.EventRecvService;
import com.freeman.cement.service.EventDataService;
import com.freeman.cement.system.BllFrame;
import com.freeman.cement.system.WebSocketServer;
import com.freeman.cement.util.file.FileUploadUtils;
import com.freeman.cement.util.hikiscUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.net.ssl.HttpsURLConnection;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class EventRecvServiceImpl implements EventRecvService {

    private static Logger logger = LoggerFactory.getLogger(EventRecvServiceImpl.class);

    @Resource
    private BjdbDao bjdbDao;
    @Resource
    private CameraDao cameraDao;
    @Resource
    private DeptDao deptDao;
    @Resource
    private MessageDao messageDao;
    @Resource
    private EventTypeDao eventTypeDao;
    @Resource
    private EventOriginDao eventOriginDao;
    @Resource
    private EventHandleService eventHandleService;
    @Resource
    private EventAnalysisServiceImplV2 analysisService;
    @Resource
    private DutyRoomService dutyRoomService;
    @Resource
    private EventDataService eventDataService;

    @Override
    public void eventRecv(String sbody) {
        /**
         * 报文解析是要解析出
         * 1、eventId 事件Id
         * 2、eventType 事件类型
         * 3、happenTime 发生事件
         * 4、cameraIndexCode 摄像头编号
         * 5、imageUrl 图片地址
         *
         * 下面解析方法要求:
         * 1、events必须为Events[]数组
         */

        //取得params
        String params = "";
        boolean needRecord = false;
        MyEvent myEvent = null;
        try {
            if (StringUtils.isBlank(sbody)) {
                logger.warn("传入的 sbody 为空");
                return;
            }

            logger.info("开始解析事件报文: {}", sbody);
            JSONObject body = JSONObject.parseObject(sbody);
            if (body == null) {
                logger.warn("解析 sbody 为 JSONObject 失败");
                needRecord = true;
                return;
            }

            Object oparams = body.get("params");
            if (oparams == null) {
                logger.warn("body 中不包含 params 字段");
                needRecord = true;
                return;
            }

            params = oparams.toString();
            logger.info("开始解析 params: {}", params);
            List<EventElement> list = analysisService.analysisEvent(params);
            if (list == null || list.isEmpty()) {
                logger.warn("解析事件列表为空");
                needRecord = true;
                return;
            }

            for (EventElement element : list) {
                try {
                    String eventId = element.getEventId();
                    String eventType = element.getEventType();
                    String happenTime = element.getHappenTime();
                    String cameraIndexCode = element.getSrcIndex();
                    String imageUrl = element.getImageUrl();

                    if (StringUtils.isNotBlank(cameraIndexCode)) {
                        List<Camera> cameras = cameraDao.selectCameraByIndexCode(cameraIndexCode);
                        Camera camera = null;
                        if (cameras != null && !cameras.isEmpty()) {
                            camera = cameras.stream()
                                .filter(s -> s.getIsEnabled() == Enabled.TRUE.getIndex())
                                .findFirst()
                                .orElse(null);
                        }
                        String sender = "system";
                        List<String> nexthandler = new ArrayList<>();
                        List<String> nexthandlerName = new ArrayList<>();

                        if (camera != null && camera.getIsRecvEnabled() == 1) {
                            //遇到未登记的摄像头，会发送给全部值班室。
                            if (camera == null || camera.getDeptDutyId() == null || camera.getDeptDutyId() == 0) {
                                List<Dept> dutys = deptDao.selectAllDutyroom();
                                dutys.forEach((s) -> {
                                    nexthandler.add("" + s.getId());
                                    nexthandlerName.add(s.getDeptName());
                                });
                            } else {
                                nexthandler.add("" + camera.getDeptDutyId());
                            }

                            QueryWrapper<MyEvent> qw = new QueryWrapper<>();
                            qw.eq("eventId", eventId);
                            qw.select("id", "eventId", "eventType", "happenTime", "cameraIndexCode", "imageUrl", "overheadInfo");
                            List<MyEvent> myEvents = bjdbDao.selectList(qw);
                            if (myEvents == null || myEvents.size() == 0) {
                                //生成报警事件 !!! 特别注意这里不一定能取到报警图片
                                myEvent = new MyEvent();
                                myEvent.setEventId(eventId);
                                myEvent.setEventType(eventType);
                                if (StringUtils.isNotBlank(eventType)) {
                                    EventType select = eventTypeDao.findEventType(eventType);
                                    if (select != null) {
                                        myEvent.setEventName(select.getEventName());
                                        myEvent.setEventLvl(select.getEventLvl());
                                        myEvent.setEventLvlName(select.getEventLvlName());
                                    } else {
                                        myEvent.setEventName("未知类型" + eventType);
                                        needRecord = true;
                                    }
                                }
                                myEvent.setHappenTime(happenTime);
                                myEvent.setCameraIndexCode(cameraIndexCode);
                                myEvent.setImageUrl(imageUrl);
                                
                                // 设置 overheadInfo
                                if (element.getOverheadInfo() != null) {
                                    myEvent.setOverheadInfo(element.getOverheadInfo());
                                    logger.info("设置事件 {} 的 overheadInfo: {}", eventId, element.getOverheadInfo());
                                } else {
                                    logger.warn("事件 {} 的 overheadInfo 为 null", eventId);
                                }
                                
                                myEvent.setStatus(ProcessingFlow.UNTREATED.getIndex());
                                myEvent.setOrigin(sbody);
                                if(camera != null && camera.getDeptDutyId() != null) {
                                    myEvent.setDutyRoomId(camera.getDeptDutyId());
                                }
                                if (StringUtils.isBlank(eventType) || StringUtils.isBlank(cameraIndexCode)) {
                                    needRecord = true;
                                }

                                // 检查值班室订阅过滤
                                if (camera != null && camera.getDeptDutyId() != null) {
                                    boolean isSubscribed = dutyRoomService.Check(camera.getDeptDutyId(), eventType);
                                    if (!isSubscribed) {
                                        logger.info("值班室[{}]未订阅事件类型[{}]，跳过处理", camera.getDeptDutyId(), eventType);
                                        continue;
                                    }
                                }

                                //生成初始的处置记录，并存入处警数据库
                                myEvent.setStatus(ProcessingFlow.UNTREATED.getIndex());
                                myEvent.setOrigin(sbody);
                                //将此次事件存入数据库
                                if (needRecord) {
                                    myEvent.setOrigin(sbody);
                                }
                                logger.info("准备保存事件到数据库，事件信息：eventId={}, eventType={}, overheadInfo={}", 
                                    myEvent.getEventId(), myEvent.getEventType(), myEvent.getOverheadInfo());
                                if (!(bjdbDao.addEvent(myEvent) > 0)) {
                                    logger.error("保存事件到数据库失败，事件信息：eventId={}, eventType={}, overheadInfo={}", 
                                        myEvent.getEventId(), myEvent.getEventType(), myEvent.getOverheadInfo());
                                } else {
                                    logger.info("成功保存事件到数据库，事件信息：eventId={}, eventType={}, overheadInfo={}", 
                                        myEvent.getEventId(), myEvent.getEventType(), myEvent.getOverheadInfo());
                                }
                                needRecord = false;

                                //生成处警记录
                                eventHandleService.handleNewEvent(myEvent, sender, sender, nexthandler, nexthandlerName);

                                //有图片才进行报警推送报警推送
                                if (StringUtils.isNotBlank(myEvent.getImageUrl())) {
                                    pushNewEventMsg(sender, nexthandler, myEvent);
                                }

                                if(StringUtils.isNotBlank(imageUrl)) {
                                    try {
                                        logger.info("准备下载事件图片，原始imageUrl: {}", imageUrl);
                                        String actualUrl = null;
                                        
                                        // 尝试解析为JSON
                                        try {
                                            JSONObject jsonObj = JSONObject.parseObject(imageUrl);
                                            if (jsonObj != null) {
                                                // 如果是JSON格式，使用hikiscUtil获取URL
                                                String apiResponse = hikiscUtil.getPicUrlByJsonStr(imageUrl);
                                                logger.info("海康API响应: {}", apiResponse);
                                                
                                                if (StringUtils.isNotBlank(apiResponse)) {
                                                    HikResultObject ro = JSONObject.parseObject(apiResponse, HikResultObject.class);
                                                    if (ro != null && "0".equals(ro.getCode()) && StringUtils.isNotBlank(ro.getData())) {
                                                        JSONObject data = JSONObject.parseObject(ro.getData());
                                                        actualUrl = data.getString("picUrl");
                                                    }
                                                }
                                            }
                                        } catch (Exception e) {
                                            // 如果不是JSON格式，可能是直接的URL
                                            logger.info("imageUrl不是JSON格式，尝试作为直接URL处理");
                                            if (imageUrl.startsWith("http://") || imageUrl.startsWith("https://")) {
                                                actualUrl = imageUrl;
                                            }
                                        }
                                        
                                        if (StringUtils.isNotBlank(actualUrl)) {
                                            logger.info("获取到实际图片URL: {}", actualUrl);
                                            // 下载并保存图片
                                            Map<String, String> picMap = eventDataService.getEventPicMap(actualUrl);
                                            if(picMap != null && picMap.containsKey("url")) {
                                                String picUrl = picMap.get("url");
                                                myEvent.setPicUrl(picUrl);
                                                // 更新数据库中的图片URL
                                                bjdbDao.updatePicUrl(myEvent.getId(), picUrl);
                                                logger.info("成功更新事件图片URL到数据库，事件ID: {}, 图片URL: {}", myEvent.getId(), picUrl);
                                            }
                                        } else {
                                            logger.error("无法获取有效的图片URL");
                                        }
                                    } catch(Exception e) {
                                        logger.error("下载事件图片失败: {}", e.getMessage());
                                    }
                                }
                            }
                        }
                    } else {
                        logger.info("eventRecv--->" + happenTime + ":接收到没有存储在本地数据库的摄像头发出的报警事件，摄像头[" + cameraIndexCode + "]，事件类型[" + eventType + "]，报警图片信息[" + imageUrl + "]");
                    }
                } catch (Exception e) {
                    logger.error("处理事件时发生错误: {}", e.getMessage(), e);
                    needRecord = false;
                }
            }
        } catch (Exception e) {
            logger.error("解析事件报文时发生错误: {}", e.getMessage(), e);
            needRecord = true;
        }

        //如果解析有误、解析不全，记录报文
        if (needRecord) {
            if (myEvent == null) {
                myEvent = new MyEvent();
            }
            myEvent.setOrigin(sbody);
            bjdbDao.addEvent(myEvent);
        }
    }

    private void pushNewEventMsg(String sender, List<String> nexthandler, MyEvent myEvent)
    {
        logger.info("准备推送新事件消息，事件ID: {}, 发送者: {}, 接收者数量: {}", myEvent.getEventId(), sender, nexthandler.size());
        
        for (String next : nexthandler) {
            JSONObject message = new JSONObject();
            message.put("from", sender);
            message.put("msg", "发生报警事件");
            message.put("event", myEvent);
            Message msg = new Message();
            msg.setContent(message.toJSONString());
            msg.setEventId(myEvent.getEventId());
            msg.setSender(sender);
            msg.setSendtime(new Date());
            msg.setReceiveDutyId(NumberUtils.toInt(next));
            msg.setReadtimes(0);

            logger.info("准备向值班室[{}]推送事件消息", next);
            // 获取在线用户列表
            List<User> onlineUsers = new ArrayList<>(BllFrame.loginUsrsCache.values());
            logger.info("准备推送消息到值班室，当前在线用户列表: {}", 
                onlineUsers.stream()
                    .map(u -> String.format("[username: %s, deptId: %s]", u.getUsername(), u.getDeptId()))
                    .collect(Collectors.joining(", ")));
            
            // 打印缓存内容
            logger.info("当前缓存内容: {}", 
                BllFrame.loginUsrsCache.entrySet().stream()
                    .map(e -> String.format("[%s: %s]", e.getKey(), e.getValue().getUsername()))
                    .collect(Collectors.joining(", ")));

            // 过滤出指定值班室的在线用户
            List<User> dutyRoomUsers = onlineUsers.stream()
                .filter(user -> user.getDeptId() != null && user.getDeptId().equals(next))
                .collect(Collectors.toList());
            
            logger.info("值班室[{}]的在线用户: {}", 
                next,
                dutyRoomUsers.stream()
                    .map(u -> String.format("[username: %s, deptId: %s]", u.getUsername(), u.getDeptId()))
                    .collect(Collectors.joining(", ")));

            final int[] pushCount = {0};
            BllFrame.loginUsrsCache.forEach((k, v) -> {
                boolean deptMatch = Integer.toString(v.getDeptId()).equals(next);
                logger.info("遍历用户[{}], 部门ID[{}], 是否匹配目标部门[{}]: {}", 
                    k, v.getDeptId(), next, deptMatch);
                if (deptMatch) {
                    logger.info("找到值班室[{}]的在线用户[{}]，准备推送消息，用户token: {}", next, k, v.getToken());
                    if (WebSocketServer.PushToUser(k, msg.getContent())) {
                        pushCount[0]++;
                        logger.info("成功向用户[{}]推送事件消息", k);
                    } else {
                        logger.warn("向用户[{}]推送事件消息失败", k);
                    }
                }
            });
            logger.info("值班室[{}]的消息推送完成，成功推送数: {}", next, pushCount[0]);

            //将消息存入消息数据库
            messageDao.addMessage(msg);
            logger.info("事件消息已保存到数据库，消息ID: {}", msg.getId());
        }
    }

    @Override
    public void eventRecord(String record) {
        eventOriginDao.addEventRecord(record, new Date());
    }

    @Override
    public ResponseResult eventRecvTest(String sbody) {
        /**
         * 报文解析是要解析出
         * 1、eventId 事件Id
         * 2、eventType 事件类型
         * 3、happenTime 发生事件
         * 4、cameraIndexCode 摄像头编号
         * 5、imageUrl 图片地址
         *
         * 下面解析方法要求:
         * 1、events必须为Events[]数组
         */

        //取得params
        String params = "";
        MyEvent myEvent = null;
        try {
            JSONObject body = JSONObject.parseObject(sbody);
            Object oparams = body.get("params");
            if (oparams != null)
                params = oparams.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }

        //解析params
        if (StringUtils.isNotBlank(params)) {
            List<EventElement> list = analysisService.analysisEventTest(params);
            return ResponseResult.success(list);
        } else {
            return null;
        }
    }

}
